home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / ImageWriter--custom dialogs / OldApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-15  |  37.7 KB  |  1,351 lines  |  [TEXT/MPS ]

  1. /*
  2.     copyright © 1992-1996 Apple Computer Inc.  All rights reserved.
  3.     
  4.     OldApp.c
  5.     This file implements old application message overrides for the specific driver.
  6.     
  7.     Included in this file is the old PrintRecord emulation.  Note that the ImageWriter
  8.     PrintRecord is a wonder of misdirection and special cases.  You'll have fun
  9.     figuring out the code - so unless you really want to exactly emulate the ImageWriter
  10.     pages, you shouldn't spend too much time looking at this code.
  11.     
  12.     Modification history
  13.     7/23/92            TED                New file today
  14.     12/20/93        dmh                Sync'd with the shipping 1.0b3 GX driver.
  15.     12/22/93        dmh                Added custom dialog code.
  16.     12/09/94        dmh                Corrected illegal use of lUser
  17.                                     PrDialogRec fields, and corrected
  18.                                     disposal of gloabal data.  This resulted
  19.                                     in removal of gxStlDialog override and
  20.                                     the addition of a gxPrDlgMain override.
  21.     12/10/94        dmh                HandleJobDlogItems wasn't sending
  22.                                     "Print" hits to the GX itemProc, so
  23.                                     dctl settings weren't being saved.
  24.                                     Fixed.
  25.      6/14/96        cn                Updated to support Universal Interfaces 2.1.
  26. */
  27.  
  28. #include <Errors.h>
  29. #include <ToolUtils.h>
  30. #include <StdIO.h>
  31. #include <StdLib.h>
  32. #include <String.h>
  33. #include <Strings.h>
  34. #include <Resources.h>
  35. #include <ToolUtils.h>
  36. #include <OSUtils.h>
  37. #include <Files.h>
  38. // #include <SysEqu.h>
  39. #include <Types.h>
  40. #include <Packages.h>
  41. #include <Memory.h>
  42. #include <Serial.h>
  43. #include <Devices.h>
  44. #include <Fonts.h>
  45. #include <Printing.h>
  46. #include <Script.h>
  47. #include <Events.h>
  48. #include <Dialogs.h>
  49. #include <FixMath.h>
  50. #include <Lists.h>
  51. #include <AppleTalk.h>
  52. #include <Menus.h>
  53. #include <Events.h>
  54. #include <Balloons.h>
  55. #include <Folders.h>
  56.  
  57. // Include the new QuickDraw GX graphics header files 
  58. #include <GXGraphics.h>
  59. #include <GraphicsLibraries.h>
  60. #include <GXMath.h>
  61. #include <QDLibrary.h>
  62. #include <FontLibrary.h>
  63. #include <GXLayout.h>
  64.  
  65. // Include the required Printing Manager header files 
  66. #include <GXPrinting.h>
  67. #include <GXPrinterDrivers.h>
  68. #include <Collections.h>
  69. #include <GXMessages.h>
  70. #include <PrintingLibraries.h>
  71.  
  72. #include <GXExceptions.h>
  73.  
  74. #include "CommonDefines.h"    // Things common to .r and .h files
  75.  
  76.  
  77. // Routines to save and retrieve our jump table globals.  These
  78. // routines are in OldApp.a
  79.  
  80. extern void                SetDialogGlobals(DialogGlobalsHdl theGlobals);
  81. extern DialogGlobalsHdl    GetDialogGlobals(void);
  82.  
  83. /* ----------------------------------------------------------------------------    */
  84. /* INTERNAL TYPEDEFS AND STRUCTURES                                                */
  85. /* ----------------------------------------------------------------------------    */
  86. /* ----------------------------------------------------------------------------    */
  87.  
  88. // ImageWriter wDev values
  89. #define kBest            0x01
  90. #define kPortrait        0x02
  91. #define kTallAdjusted    0x04
  92. #define k50Percent        0x08
  93. #define kNoGaps            0x10
  94. #define kSetResCalled    0x20
  95.  
  96. // some ImageWriter constants
  97. #define kGapSize        60        // gap at top of page in 120ths of an inch
  98. #define kSmallPlaten    16        // platen width in half inches for small IW
  99. #define kBigPlaten        27        // platen width in half inches for the 15" IW
  100.  
  101.  
  102. // Prototypes:
  103.  
  104. OSErr            UpdatePrintRecord(THPrint hPrint);
  105. OSErr            SD_ConvertPrintRecordTo(THPrint hoPrint);
  106. OSErr            SD_ConvertPrintRecordFrom(gxUniversalPrintRecordHdl huPrint);
  107. OSErr            SD_PrintRecordToJob(THPrint hPrint, gxJob theJob);
  108. OSErr            SD_PrValidate(THPrint hPrint, Boolean *wasChanged);
  109.  
  110. OSErr            CreateAndStoreGlobals(DialogGlobalsHdl *dlogGlobals);
  111. void            DisposeGlobals(void);
  112.  
  113. OSErr            SD_PrDlgMain(THPrint hPrint, PDlgInitProcPtr initProc,
  114.                              Boolean *userConfirmed);
  115.  
  116. OSErr            SD_PrJobInit(THPrint hPrint, TPPrDlg *pDlg);
  117. OSErr            InitJobDlogData(TPPrDlg pDlg);
  118. pascal void        HandleJobDlogItems(TPPrDlg pDlg, short itemNo);
  119. OSErr            SD_PrStlDialog(THPrint hPrint, Boolean *userConfirmed);
  120. OSErr            SD_PrStlInit(THPrint hPrint, TPPrDlg *pDlg);
  121.  
  122. OSErr            InitStlDlogData(TPPrDlg pDlg);
  123. pascal void        HandleStlDlogItems(TPPrDlg pDlg, short itemNo);
  124.  
  125. void            DoOptionsDialog();
  126. pascal Boolean    OptionsDlogFilterProc(DialogPtr theDialog, EventRecord *theEvent,
  127.                                       short *itemHit);
  128. void            HandleOptionsDlogItems(short itemNo);
  129.  
  130. void            ToggleControl(void **itemH);
  131. void            DrawFlippedPict(void);
  132. void            SetCurFlip(DialogPtr theDialog, char curFlipping);
  133.  
  134. //    --------------- start of the good stuff ------------
  135.  
  136.  
  137. /* ----------------------------------------------------------------------------    */
  138. /* INTERNAL ROUTINES                                                            */
  139. /* ----------------------------------------------------------------------------    */
  140.  
  141. OSErr    UpdatePrintRecord(THPrint hPrint)
  142. {
  143.     OSErr                        anErr;
  144.     gxUniversalPrintRecordHdl     huPrint = (gxUniversalPrintRecordHdl) hPrint;
  145.     gxUniversalPrintRecordPtr     puPrint;
  146.     short                        devVRes, devHRes, appVRes, appHRes;
  147.     short                        cPlaten;
  148.  
  149.     // convert to universal format
  150.     anErr = SD_ConvertPrintRecordTo(hPrint);
  151.     if (anErr == noErr)
  152.         {
  153.         // determine application & device resolutions, based upon quality mode, tall adjusted
  154.         // setting, and if the app called SetRsl:
  155.         //    draft - 80(h)*72(v)
  156.         //    faster - 80(h)*72(v)
  157.         //    best - 160(h)*144(v)
  158.         //
  159.         //    draft (tall adjusted) - 72*72
  160.         //    faster (tall adjusted) - 72*72
  161.         //    best (tall adjusted) - 144*144
  162.         
  163.         puPrint = *huPrint;
  164.         if (puPrint->options & gxPreciseBitmap)
  165.             switch(puPrint->qualityMode)
  166.                 {
  167.                 case gxDraftQuality:
  168.                 case gxFasterQuality:
  169.                     devVRes = devHRes = 72;
  170.                     appVRes = appHRes = 72;
  171.                     break;
  172.                     
  173.                 case gxBestQuality:
  174.                     devVRes = devHRes = 144;
  175.                     appVRes = appHRes = 72;
  176.                     break;
  177.                 }
  178.         else
  179.             switch(puPrint->qualityMode)
  180.                 {
  181.                 case gxDraftQuality:
  182.                 case gxFasterQuality:
  183.                     appVRes = devVRes = 72;
  184.                     appHRes = devHRes = 80;
  185.                     break;
  186.                     
  187.                 case gxBestQuality:
  188.                     devVRes = 144;
  189.                     devHRes = 160;
  190.                     appVRes = 72;
  191.                     appHRes = 80;
  192.                     break;
  193.                 }
  194.             
  195.         // SetRsl was called?  Use the resolution specified by the application
  196.         if (puPrint->appVRes != 72)
  197.             {
  198.             appVRes = devVRes = puPrint->appVRes;
  199.             appHRes = devHRes = puPrint->appHRes;
  200.             }
  201.             
  202.         // finally, store the app & device resolutions
  203.         puPrint->devVRes = devVRes;
  204.         puPrint->devHRes = devHRes;
  205.         puPrint->appVRes = appVRes;
  206.         puPrint->appHRes = appHRes;
  207.         
  208.         // here we do page size calculations
  209.         // Please note that this code is confusing - it's purpose is to emulate
  210.         // the existing ImageWriter driver's page size.  Most drivers would not
  211.         // do this - the existing in the system probably is good enough.
  212.         {
  213.         long        pageGap;                // gap at top of page
  214.         long        dvPaper, dhPaper;        // paper size at device res
  215.         long        dvPage, dhPage;            // page size at device res
  216.         long        scanLines, scanBits;    // # of scan lines or bits on page
  217.         long        maxH;                    // maximum width
  218.         long        hOff, vOff;                // margins (horiz & vert) to get paper rect from page rect
  219.         
  220.         // gap at the top of the page in pixels
  221.         pageGap = (kGapSize * appVRes) / 120;
  222.         if (puPrint->options & gxBiggerPages)
  223.             pageGap = 0;
  224.             
  225.         // figure out paper size in application space pixels
  226.         dvPaper = (puPrint->pageV * appVRes) / 120;
  227.         dhPaper = (puPrint->pageH * appHRes) / 120;
  228.                 
  229.         // vertically, align to the head height of 8 pixels
  230.         scanLines = ((dvPaper - pageGap) >> 3) << 3;
  231.         
  232.         // horizontally, allow the biggest width we can handle
  233.         cPlaten = kSmallPlaten;
  234.         if (puPrint->pageH > (9*120) )
  235.             cPlaten = kBigPlaten;
  236.             
  237.         maxH = (cPlaten * appHRes) >> 1;
  238.         if (maxH > dhPaper)
  239.             maxH = dhPaper;
  240.         scanBits = (maxH >> 4) << 4;
  241.         
  242.         if (puPrint->orientation == gxPortraitOrientation)
  243.             {
  244.             // portrait
  245.             
  246.             dhPage = scanBits;
  247.             dvPage = scanLines;
  248.             
  249.             hOff = (dhPage - dhPaper) >> 1;
  250.             vOff = -pageGap;
  251.             }
  252.         else
  253.             {
  254.             // landscape
  255.             
  256.             dhPage = scanLines;
  257.             dvPage = scanBits;
  258.             
  259.             // reverse the paper definition as well
  260.             {
  261.             long iTemp = dhPaper;
  262.             dhPaper = dvPaper;
  263.             dvPaper = iTemp;
  264.             }
  265.             
  266.             hOff = -pageGap;
  267.             vOff = (dvPage - dvPaper) >> 1;
  268.             }
  269.             
  270.         // 50% reduction?  scale everything by 2X
  271.         if (puPrint->options & gxUserFlag0)
  272.             {
  273.             dhPage <<= 1;
  274.             dvPage <<= 1;
  275.             dhPaper <<= 1;
  276.             dvPaper <<= 1;
  277.             hOff <<= 1;
  278.             vOff <<= 1;
  279.             }
  280.             
  281.         // set the page and paper in app space
  282.         puPrint->appPage.left         = puPrint->appPage.top = 0;
  283.         puPrint->appPage.right         = dhPage;
  284.         puPrint->appPage.bottom     = dvPage;
  285.         
  286.         puPrint->appPaper.left         = hOff;
  287.         puPrint->appPaper.top         = vOff;
  288.         puPrint->appPaper.right     = dhPaper + hOff;
  289.         puPrint->appPaper.bottom     = dvPaper + vOff;
  290.                 
  291.         // from page, scale up to device space (in case some weenie decides to look at that)
  292.         puPrint->devPage.left         = puPrint->devPage.top = 0;
  293.         puPrint->devPage.right         = dhPage * devHRes / appHRes;
  294.         puPrint->devPage.bottom     = dvPage * devVRes / appVRes;
  295.         }
  296.         
  297.         // convert back to non-universal format
  298.         anErr = SD_ConvertPrintRecordFrom((gxUniversalPrintRecordHdl) hPrint);
  299.         }
  300.         
  301.     return(anErr);
  302.     
  303. } // UpdatePrintRecord
  304.  
  305. //<FF>
  306. /* ----------------------------------------------------------------------------    */
  307. /* MESSAGE OVERRIDES                                                            */
  308. /* ----------------------------------------------------------------------------    */
  309. OSErr SD_ConvertPrintRecordTo(THPrint hoPrint)
  310. /*
  311.     This call takes a print record in old style (driver specific) format, and
  312.     converts it to the format of "gxUniversalPrintRecordHdl"
  313. */
  314. {
  315.     TPPrint                        poPrint;            // pointer to old style print record
  316.     gxUniversalPrintRecordHdl    huPrint = (gxUniversalPrintRecordHdl) hoPrint;    // handle to universal print record
  317.     gxUniversalPrintRecordPtr    puPrint;            // pointer to universal print record
  318.     short                        qualityMode;        // cached quality mode
  319.     short                        wDev;                // cached wDev
  320.     
  321.     // cache pointers for size and speed
  322.     puPrint = *huPrint;
  323.     poPrint = *hoPrint;
  324.     wDev = poPrint->prStl.wDev;
  325.     
  326.     // determine quality mode
  327.     if (poPrint->prJob.bJDocLoop == 0)
  328.         qualityMode = gxDraftQuality;
  329.     else
  330.         {
  331.         if (wDev & kBest)
  332.             qualityMode = gxBestQuality;
  333.         else
  334.             qualityMode = gxFasterQuality;
  335.         }
  336.         
  337.     // universal feed is the inverse of our feed
  338.     puPrint->feed            =    1-(poPrint->prStl.feed);
  339.     
  340.     // wDev 0x02 means portrait, else landscape
  341.     if (wDev & kPortrait) 
  342.         puPrint->orientation    =    gxPortraitOrientation;
  343.     else
  344.         {
  345.         puPrint->orientation    =    gxLandscapeOrientation;
  346.         
  347.         // landscape disabled draft, forces tall adjusted
  348.         if (qualityMode == gxDraftQuality)
  349.             qualityMode = gxFasterQuality;
  350.         wDev |= kTallAdjusted;
  351.         }
  352.         
  353.     // copies are in iCopies field (wow.)
  354.     puPrint->actualCopies        =    poPrint->prJob.iCopies;
  355.     
  356.     // store our flags
  357.     puPrint->options = 0;
  358.     
  359.     // tall adjusted
  360.     if (wDev & kTallAdjusted) 
  361.         puPrint->options |= gxPreciseBitmap;
  362.         
  363.     // 50% reduction
  364.     if (wDev & k50Percent) 
  365.         {
  366.         puPrint->options |= gxUserFlag0;
  367.         puPrint->reduction = 50;
  368.         
  369.         // for 50% reduction, we always return faster to the application
  370.         qualityMode = gxFasterQuality;
  371.         }
  372.     else
  373.         puPrint->reduction = 100;
  374.         
  375.     // no gaps
  376.     if (wDev & kNoGaps) 
  377.         puPrint->options |= gxBiggerPages;
  378.     
  379.     // finally, store quality mode    
  380.     puPrint->qualityMode = qualityMode;
  381.     
  382.     // and we can't have any errors - because this code is too godlike.
  383.     return(noErr);
  384.     
  385. } // SD_ConvertPrintRecordTo
  386.  
  387. //<FF>
  388. /* ----------------------------------------------------------------------------    */
  389. OSErr SD_ConvertPrintRecordFrom(gxUniversalPrintRecordHdl huPrint)
  390. /*
  391.     This call takes a print record in universal format and converts it
  392.     to old style (driver specific) format.
  393.     
  394.     Note: for the ImageWriter, I'm filling in way more things than theoretically
  395.     I need to.  However, since the ImageWriter is one of the oldest print drivers,
  396.     there is much more of a chance that someone assumes something about one or
  397.     more of the fields.
  398. */
  399. {
  400.     gxUniversalPrintRecordPtr    puPrint;            // pointer to universal print record
  401.     THPrint                        hoPrint = (THPrint) huPrint;    // handle to old style print record
  402.     TPPrint                        poPrint;            // pointer to old style print record
  403.     short                        options;            // cached universal options
  404.     short                        qualityMode;        // cached universal quality mode
  405.     short                        actualCopies;        // cached universal copies
  406.     
  407.     // cache pointers for size and speed
  408.     puPrint = *huPrint;
  409.     poPrint = *hoPrint;
  410.  
  411.     // save away fields within the universal record that we'll be stomping over
  412.     // as we convert
  413.     options         = puPrint->options;
  414.     qualityMode     = puPrint->qualityMode;
  415.     actualCopies    = puPrint->actualCopies;
  416.     
  417.     poPrint->iPrVersion            = 4;        // used to be 3, but this is
  418.                                             // a new driver.  We support versions
  419.                                             // 3 and 4
  420.     poPrint->prInfo.iDev        = 0;        // always zero for the ImageWriter
  421.     
  422.     // skip remaining fields in prInfo because they are unchanged
  423.     
  424.     // determine the wDev
  425.     {
  426.     short    wDev;
  427.     
  428.     // this is the wDev value for the ImageWriter
  429.     wDev = 0x0100;
  430.     
  431.     if (puPrint->orientation == gxPortraitOrientation)
  432.         wDev |= kPortrait;
  433.     else
  434.         {
  435.         // for landscape, disable draft and force tall adjusted
  436.         if (qualityMode == gxDraftQuality)
  437.             qualityMode = gxFasterQuality;
  438.             
  439.         options |= gxPreciseBitmap;
  440.         }
  441.     
  442.     // user options
  443.     if (options & gxPreciseBitmap)
  444.         wDev |= kTallAdjusted;
  445.     if (options & gxUserFlag0)
  446.         {
  447.         wDev |= k50Percent;
  448.         qualityMode = gxFasterQuality;
  449.         }
  450.  
  451.     if (options & gxBiggerPages)
  452.         wDev |= kNoGaps;
  453.         
  454.     // if the application's resolution isn't 72 - then clearly SetRsl must have been called
  455.     // to change it.
  456.     if (poPrint->prInfo.iVRes != 72)
  457.         {
  458.         wDev |= kSetResCalled;
  459.         qualityMode = gxBestQuality; /* ?? qualityMode == gxBestQuality */
  460.         }
  461.         
  462.     if (qualityMode == gxBestQuality)
  463.         wDev |= kBest;
  464.         
  465.         
  466.     // and finally, save away that short value we worked so hard to determine
  467.     poPrint->prStl.wDev = wDev;
  468.     }
  469.  
  470.     // other fields in prStl remain the same
  471.     
  472.     poPrint->prStl.bPort     = 0;
  473.     poPrint->prStl.feed     = 1 - (puPrint->feed);
  474.     poPrint->prInfoPT.iDev     = (qualityMode == gxBestQuality) ? -768 : 0;
  475.  
  476.     // other fields in prInfoPT remain the same
  477.     {
  478.     Rect    rPage = poPrint->prInfoPT.rPage;
  479.     
  480.     // calculate some fields we don't use - in case someone really wants to look at
  481.     // them for some reason
  482.     poPrint->prXInfo.iRowBytes    = rPage.right >> 3;
  483.     poPrint->prXInfo.iBandV        = 32;
  484.     poPrint->prXInfo.iBandH        = poPrint->prXInfo.iRowBytes << 3;
  485.     poPrint->prXInfo.iDevBytes    = poPrint->prXInfo.iRowBytes * 
  486.                                     poPrint->prXInfo.iBandV + 
  487.                                     poPrint->prXInfo.iBandH;
  488.     poPrint->prXInfo.iBands        = (rPage.bottom+(poPrint->prXInfo.iBandV-1)) / poPrint->prXInfo.iBandV;
  489.     poPrint->prXInfo.bPatScale     = (qualityMode == gxBestQuality) ? -2 : 0;
  490.     poPrint->prXInfo.bUlThick     = 1;
  491.     poPrint->prXInfo.bUlOffset     = 1;
  492.     poPrint->prXInfo.bUlShadow     = 1;
  493.     poPrint->prXInfo.scan        = (poPrint->prStl.wDev & kPortrait) ? 0 : 2;
  494.     poPrint->prXInfo.bXInfoX    = 0;
  495.     }
  496.     
  497.     // other fields in prJob remain the same
  498.     poPrint->prJob.iCopies        = actualCopies;
  499.     poPrint->prJob.bJDocLoop    = (qualityMode == gxDraftQuality) ? 0 : 1;
  500.     
  501.     // this routine is so studly, there can be no errors
  502.     return(noErr);    
  503.     
  504. } // SD_ConvertPrintRecordFrom
  505.  
  506.  
  507. //<FF>
  508. /* ----------------------------------------------------------------------------    */
  509. OSErr SD_PrintRecordToJob(THPrint hPrint, gxJob theJob)
  510. /*
  511.     We convert the "tall adjusted" setting into the correct rendering option for
  512.     the job collection.
  513. */
  514. {
  515.     OSErr    anErr;
  516.     Handle     jobQualitySettingsHdl;    
  517.     
  518.     anErr = Forward_GXPrintRecordToJob(hPrint, theJob);
  519.     if (anErr == noErr)
  520.         {
  521.         long imagewriterOptions = kSuperRes;
  522.         
  523.         if ((**hPrint).prStl.wDev & kSetResCalled)
  524.             {
  525.             Collection            jobCollection = GXGetJobCollection(GXGetJob());
  526.             gxQualityInfo        *qualitySettings;
  527.     
  528.  
  529.             // get old info and replace it with final quality
  530.  
  531.  
  532.             jobQualitySettingsHdl = NewHandle(0);
  533.             anErr = MemError();
  534.             nrequire(anErr, FailedNewHandle);
  535.  
  536.             anErr = GetCollectionItemHdl (     jobCollection,
  537.                                                 gxQualityTag,
  538.                                                  gxPrintingTagID,
  539.                                                jobQualitySettingsHdl );
  540.  
  541.             if (anErr == collectionItemNotFoundErr) 
  542.                 {
  543.                 Str255            bestString, roughString;
  544.                 Size            count1, count2;
  545.                 Ptr                p;
  546.         
  547.                 GetIndString( bestString, kOldQualityID, kBestString);
  548.                 GetIndString( roughString, kOldQualityID, kRoughString);
  549.  
  550.                 SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
  551.                 anErr = MemError();
  552.                 nrequire( anErr, FailedSetHandleSize );
  553.                         
  554.                 qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  555.                 
  556.                 qualitySettings->disableQuality = false;
  557.                 qualitySettings->defaultQuality = 1;
  558.                 qualitySettings->currentQuality = 1;
  559.                 qualitySettings->qualityCount = 2;
  560.         
  561.                 count1 = bestString[0]+1;
  562.                 p = qualitySettings->qualityNames;
  563.                 BlockMove( bestString, p, count1 );
  564.         
  565.                 count2 = roughString[0]+1;
  566.                 p += count1;
  567.                 BlockMove( roughString, p, count2 );
  568.         
  569.                 }
  570.             else
  571.                 qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  572.  
  573.             (qualitySettings->currentQuality = qualitySettings->qualityCount-1);
  574.  
  575.             anErr = AddCollectionItemHdl (     jobCollection,
  576.                                             gxQualityTag,
  577.                                             gxPrintingTagID,
  578.                                             jobQualitySettingsHdl );
  579.                                                  
  580.             if (anErr == noErr)
  581.                 (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
  582.                 
  583.             DisposHandle(jobQualitySettingsHdl);
  584.             }
  585.  
  586.         if ((**hPrint).prStl.wDev & kTallAdjusted)
  587.             imagewriterOptions = 0;
  588.             
  589.         if (anErr == noErr)
  590.             anErr = AddCollectionItem(GXGetJobCollection(theJob), 
  591.                         DriverCreator,
  592.                         0,
  593.                         sizeof(imagewriterOptions),
  594.                         &imagewriterOptions);
  595.         }
  596.  
  597. FailedNewHandle:        
  598.     return(anErr);
  599.  
  600. FailedSetHandleSize:
  601.     DisposHandle(jobQualitySettingsHdl);
  602.     return(anErr);
  603.     
  604. } // SD_PrintRecordToJob
  605.  
  606. //<FF>
  607. /* ----------------------------------------------------------------------------    */
  608. OSErr SD_PrValidate(    THPrint hPrint,                 // old style print record
  609.                         Boolean *wasChanged)            // was the print record changed?
  610. /*
  611.     This call validates the current print record.  It's fairly simplistic (as were
  612.     all of the old drivers) - the wDev or versions don't match the current, we call
  613.     PrintDefault.  Otherwise, we call UpdatePrintRecord - to allow the driver to sanity
  614.     check any internal fields.
  615.     
  616. */
  617. {
  618.     unsigned short    wDev;                        // note: if this were signed, the shift below would fail                    
  619.     Boolean            recordIsInvalid = true;            
  620.     OSErr            anErr = noErr;
  621.     
  622.     // check the wDev.  The upper byte must be equal to our idea of the wDev
  623.         
  624.     wDev =  (**hPrint).prStl.wDev;    
  625.     wDev >>= 8;                                // get just the device ID
  626.  
  627.     // If the device id is equal, then check the version number of the print record.
  628.     //    Only if that is also equal to the current version, will we return false (valid).
  629.         
  630.     if (     (wDev == 1) 
  631.         &&
  632.             (
  633.             ( ((**hPrint).iPrVersion) == 3 ) ||
  634.             ( ((**hPrint).iPrVersion) == 4 ) 
  635.             )
  636.         )
  637.         recordIsInvalid = false;
  638.             
  639.  
  640.     // If the the print record is not valid, then return the default print record.
  641.     // Otherwise, update the print record, based on the application's calls
  642.     // to PrGeneral.
  643.         
  644.     if (recordIsInvalid)
  645.         PrintDefault(hPrint);
  646.     else
  647.         anErr = UpdatePrintRecord(hPrint);
  648.         
  649.     *wasChanged = recordIsInvalid;
  650.     
  651.     return (anErr);
  652.     
  653. } // SD_PrValidate
  654.  
  655.  
  656. // This routine creates a handle for our dialog globals,
  657. // and stores it in the space we allocated at the end of our
  658. // jump table.
  659.  
  660. OSErr CreateAndStoreGlobals(DialogGlobalsHdl *dlogGlobalsHdl)
  661. {
  662.     OSErr    err;
  663.  
  664.     *dlogGlobalsHdl = (DialogGlobalsHdl) TempNewHandle(sizeof(DialogGlobals), &err);
  665.     nrequire(err, TempNewHandle_Failed);
  666.  
  667. // Clear the data.
  668.  
  669.     (**dlogGlobalsHdl)->inStyleDialog = false;
  670.     (**dlogGlobalsHdl)->originalItemProc = nil;
  671.     (**dlogGlobalsHdl)->optionsDialog = nil;
  672.     (**dlogGlobalsHdl)->flippedPicts = nil;
  673.  
  674.     SetDialogGlobals(*dlogGlobalsHdl);
  675.  
  676. TempNewHandle_Failed:
  677.     return err;
  678. }
  679.  
  680.  
  681. // This routine disposes of our dialog globals.
  682.  
  683. void DisposeGlobals()
  684. {
  685.     DialogGlobalsHdl    dlogGlobalsHdl;
  686.     char                idx;
  687.  
  688. // Get our dialog globals.
  689.  
  690.     dlogGlobalsHdl = GetDialogGlobals();
  691.     require(dlogGlobalsHdl != nil, NoGlobals);
  692.  
  693. // If allocated, dispose of the options dialog and release the PICT
  694. // resources we used there.  When done, dispose of the pointer that
  695. // we used to hold the PicHandles.
  696.  
  697.     if ((*dlogGlobalsHdl)->optionsDialog)
  698.         DisposeDialog((*dlogGlobalsHdl)->optionsDialog);
  699.  
  700.     if ((*dlogGlobalsHdl)->flippedPicts)
  701.     {
  702.         for (idx = 0; idx< 4; idx++)
  703.             if ((*dlogGlobalsHdl)->flippedPicts->pict[idx])
  704.                 ReleaseResource((Handle) (*dlogGlobalsHdl)->flippedPicts->pict[idx]);
  705.  
  706.         DisposPtr((Ptr) (*dlogGlobalsHdl)->flippedPicts);
  707.     }
  708.  
  709. // Finally, dispose of the handle to our globals, and store nil
  710. // in it's place.  This indicates that no valid globals are
  711. // allocated.
  712.  
  713.     DisposeHandle((Handle) dlogGlobalsHdl);
  714.     SetDialogGlobals(nil);
  715.  
  716. NoGlobals:;
  717. }
  718.  
  719.  
  720. OSErr SD_PrDlgMain(THPrint hPrint, PDlgInitProcPtr initProc, Boolean *userConfirmed)
  721. {
  722.     OSErr                err;
  723.     DialogGlobalsHdl    dlogGlobalsHdl;
  724.     
  725. // Forward the message so that GX handles the Style or Job dialog.
  726. // On return, retrieve the globals that our init proc created.
  727.  
  728.     err = Forward_GXPrDlgMain(hPrint, initProc, userConfirmed);
  729.  
  730.     dlogGlobalsHdl = GetDialogGlobals();
  731.     require(dlogGlobalsHdl != nil, NoGlobals);
  732.     
  733.  
  734. // If we just executed the Style dialog, and the user confirmed the
  735. // dialog, change our format's flipping.  Regardless of the dialog,
  736. // dispose of the globals our initProc allocated.
  737.  
  738.     if ((*dlogGlobalsHdl)->inStyleDialog && *userConfirmed)
  739.     {
  740.         FourPicts    *flippedPicts = (*dlogGlobalsHdl)->flippedPicts;
  741.  
  742.         SetFormatFlipping(flippedPicts->curFlipping, GXGetJobFormat(GXGetJob(), 1));
  743.     }
  744.  
  745.     DisposeGlobals();
  746.     
  747. NoGlobals:
  748.     return err;
  749. }
  750.  
  751.  
  752. /* ----------------------------------------------------------------------------    */
  753. // SD_PrJobInit is an override for GXPrJobInit.  Since we need to handle
  754. // some non-dctl items in this dialog, we override this message and call
  755. // InitJobDlogData to prepare the dialog.
  756.  
  757. OSErr SD_PrJobInit(THPrint hPrint, TPPrDlg *pDlg)
  758. {
  759.     OSErr    anErr;
  760.     Boolean    disableDraft     = false;
  761.     Boolean    disableAll         = false;
  762.     short    wDev             = (**hPrint).prStl.wDev;
  763.     short    idx;
  764.     Rect    box;
  765.     Handle    item;
  766.     short    type;
  767.  
  768.     anErr = Forward_GXPrJobInit(hPrint, pDlg);
  769.     nrequire(anErr, Forward_Failed);
  770.  
  771.     if (wDev & k50Percent)
  772.         disableAll = true;
  773.         
  774.     if (wDev & kSetResCalled)
  775.         disableAll = true;
  776.         
  777.     if (!(wDev & kPortrait))
  778.         disableDraft = true;
  779.     
  780.     // disable any controls we need to
  781.     for (idx = 6; idx <= 8; ++idx)
  782.     {
  783.         GetDItem((DialogPtr) *pDlg, idx, &type, &item, &box);
  784.         
  785.         if ( (disableAll) || ((disableDraft) && (idx == 8) ) )
  786.             HiliteControl((ControlHandle) item, 255);
  787.     }
  788.  
  789.     InitJobDlogData(*pDlg);
  790.  
  791. Forward_Failed:
  792.     return anErr;
  793.  
  794. } // SD_PrJobInit
  795.  
  796.  
  797.  
  798. // InitJobDlogData is called by SD_PrJobInit to confugure our print
  799. // dialog at job init time.  We need to enforce the following rules
  800. // using our (non-dctl) quality popup menu control:
  801. //
  802. //        - 50% disables all items
  803. //        - apps that call SetRsl disable all items
  804. //        - landscape disables draft mode
  805. //
  806. // Also, we replace the dialog's item handler with our own, and store
  807. // it away for later use by HandleJobDlogItems.  This way, we can use dctl
  808. // and non-dctl items in the same dialog.
  809. //
  810. // Note that this routine requires cleanup (ie. disposal) of data, and
  811. // that's why we call DisposeGlobals from SD_PrDlgMain.
  812.  
  813. OSErr InitJobDlogData(TPPrDlg pDlg)
  814. {
  815.     OSErr                err;
  816.     short                wDev, itemType, qualMode;
  817.     THPrint                hPrint;
  818.     Handle                itemH;
  819.     Rect                itemBox;
  820.     Boolean                disableDraft, disableAll;
  821.     MenuHandle            qualMenu;
  822.     DialogGlobalsHdl    dlogGlobalsHdl;
  823.  
  824. // Create our dialog globals.
  825.  
  826.     err = CreateAndStoreGlobals(&dlogGlobalsHdl);
  827.     nrequire(err, CreateAndStoreGlobals_Failed);
  828.  
  829.  
  830. // Indicate that we're executing the Job dialog.
  831.     (*dlogGlobalsHdl)->inStyleDialog = false;
  832.  
  833.  
  834. // Get the print record handle, the driver's wDev, the handle to our
  835. // quality popup control in the job dialog, and a handle to our
  836. // quality menu.  Note that you should NOT use GetMenu to do this.
  837. // GetMenu should only be called once per menu.
  838.  
  839.     hPrint = pDlg->hPrintUsr;
  840.     wDev = (*hPrint)->prStl.wDev;
  841.     GetDItem((DialogPtr) pDlg, d_QualPopUp, &itemType, &itemH, &itemBox);
  842.     qualMenu = (MenuHandle) GetResource('MENU', r_QualPopUpMenu);
  843.  
  844.  
  845. // If we're printing at 50% reduction or PrGeneral's setRsl was used,
  846. // disable all quality settings.  If we're printing in landscape mode,
  847. // disable draft mode.
  848.  
  849.     disableAll = ((wDev & k50Percent) || (wDev & kSetResCalled))? true: false;
  850.     disableDraft = (!(wDev & kPortrait))? true:false;
  851.  
  852.     HiliteControl((ControlHandle) itemH, (disableAll)? 255:0);
  853.  
  854.     if (disableDraft)
  855.         DisableItem(qualMenu, i_DraftItem);
  856.     else
  857.         EnableItem(qualMenu, i_DraftItem);
  858.  
  859.  
  860. // Now determine the current quality mode, and set our quality control's
  861. // value to that.
  862.  
  863.     if (!disableAll)
  864.     {
  865.         if ((*hPrint)->prJob.bJDocLoop == 0)
  866.                 qualMode = 3;                    // draft mode.
  867.             else
  868.             {
  869.                 if ((*hPrint)->prStl.wDev & kBest)
  870.                     qualMode = 1;                // best mode.
  871.                 else
  872.                     qualMode = 2;                // faster mode.
  873.             }
  874.     }
  875.  
  876.     GetDItem((DialogPtr) pDlg, d_QualPopUp, &itemType, &itemH, &itemBox);
  877.     SetCtlValue((ControlHandle) itemH, qualMode);
  878.  
  879.  
  880. // Finally, save the old item handler proc (which will be used by the dctl items),
  881. // and store our driver's item proc (for our non-dctl items).
  882.  
  883.     (*dlogGlobalsHdl)->originalItemProc = pDlg->pItemProc;
  884.     pDlg->pItemProc = (PItemProcPtr) HandleJobDlogItems;
  885.  
  886. CreateAndStoreGlobals_Failed:
  887.     return err;
  888. }
  889.  
  890.  
  891. // HandleJobDlogItems is our item handling routine for the job dialog.
  892. // The only item we handle is the OK button, which simply records
  893. // our quality pop-up control settings in the print record.  All
  894. // other items are passed to the GX item handler, since they are
  895. // in our dctl resource.  This way, we get the benefits of dctls,
  896. // but we can still support non-dctl controls.
  897.  
  898. pascal void HandleJobDlogItems(TPPrDlg pDlg, short itemNo)
  899. {
  900.     short                itemType, qualMode;
  901.     Handle                itemH;
  902.     THPrint                hPrint;
  903.     Rect                itemBox;
  904.     DialogGlobalsHdl    dlogGlobalsHdl;
  905.     Ptr                    *originalItemProc;
  906.  
  907. // Retrieve our dialog globals, and from those, GX's original
  908. // itemProc.
  909.         
  910.     dlogGlobalsHdl = GetDialogGlobals();
  911.     require(dlogGlobalsHdl != nil, NoGlobals);
  912.     
  913.     originalItemProc = (*dlogGlobalsHdl)->originalItemProc;
  914.  
  915.  
  916. // If the ok button was hit, store our quality mode.  Regardless of
  917. // the item which was hit, pass control to the GX dialog item handler
  918. // routine (which we stored in InitJobDlogData).  That way, the GX
  919. // itemProc can do it's thing for dctl items.
  920.  
  921.     switch (itemNo)
  922.     {
  923.         case ok:
  924.             (pDlg)->fDoIt = (pDlg)->fDone = true;
  925.  
  926.             GetDItem((DialogPtr) pDlg, d_QualPopUp, &itemType, &itemH, &itemBox);
  927.             qualMode = GetCtlValue((ControlHandle) itemH);
  928.  
  929.             hPrint = pDlg->hPrintUsr;
  930.  
  931.             switch (qualMode)
  932.             {
  933.                 case 1:                                // best mode.
  934.                     (*hPrint)->prStl.wDev |= kBest;
  935.                     (*hPrint)->prJob.bJDocLoop = 1;
  936.                     break;
  937.             
  938.                 case 2:                                // faster mode.
  939.                     (*hPrint)->prStl.wDev = ((*hPrint)->prStl.wDev >>1) <<1;
  940.                     (*hPrint)->prJob.bJDocLoop = 1;
  941.                     break;
  942.             
  943.                 default:                            // draft mode.
  944.                     (*hPrint)->prStl.wDev = ((*hPrint)->prStl.wDev >>1) <<1;
  945.                     (*hPrint)->prJob.bJDocLoop = 0;
  946.                     break;
  947.             }
  948.             ((pascal void (*) (TPPrDlg, short)) originalItemProc) (pDlg, itemNo);
  949.             break;
  950.  
  951.         default:
  952.             ((pascal void (*) (TPPrDlg, short)) originalItemProc) (pDlg, itemNo);
  953.             break;
  954.     }
  955.  
  956. NoGlobals:;
  957. }
  958.  
  959.  
  960. // SD_PrStlInit is an override for GXPrStlInit.  Since we need to handle
  961. // some non-dctl items in this dialog, we override this message and call
  962. // InitStlDlogData to prepare the dialog.
  963.  
  964. OSErr SD_PrStlInit(THPrint hPrint, TPPrDlg *pDlg)
  965. {
  966.     OSErr    err;
  967.     
  968. // Forward the message, then initialize our data.
  969.  
  970.     err = Forward_GXPrStlInit(hPrint, pDlg);
  971.     nrequire(err, Forward_Failed);
  972.  
  973.     err = InitStlDlogData(*pDlg);
  974.  
  975. Forward_Failed:
  976.     return err;
  977. }
  978.  
  979.  
  980. // InitStlDlogData is called by SD_PrStlInit to confugure our print
  981. // dialog at job init time.
  982. //
  983. // Also, we replace the dialog's item handler with our own, and store
  984. // it away for later use by HandleJobDlogItems.  This way, we can use dctl
  985. // and non-dctl items in the same dialog.
  986. //
  987. // Note that this routine requires cleanup (ie. disposal) of data, and
  988. // that's why we call DisposeGlobals from SD_PrDlgMain.
  989.  
  990. OSErr InitStlDlogData(TPPrDlg pDlg)
  991. {
  992.     OSErr                        err = noErr;
  993.     short                        oldResFile;
  994.     gxFlipPageHorizontalInfo    hFlipInfo;
  995.     gxFlipPageVerticalInfo        vFlipInfo;
  996.     long                        itemSize;
  997.     gxFormat                    pageFormat;
  998.     DialogGlobalsHdl            dlogGlobalsHdl;
  999.     FourPicts                    *flippedPicts;
  1000.     DialogPtr                    optionsDialog;
  1001.  
  1002. // Create our dialog globals.
  1003.  
  1004.     err = CreateAndStoreGlobals(&dlogGlobalsHdl);
  1005.     nrequire(err, CreateAndStoreGlobals_Failed);
  1006.  
  1007.  
  1008. // Indicate that we're executing the Style dialog.
  1009.     (*dlogGlobalsHdl)->inStyleDialog = true;
  1010.  
  1011.  
  1012. // Save the current resource file and use our driver's.  Then,
  1013. // get our options dialog and store a pointer to it in our globals.
  1014. // Store a pointer to the options dialog, in our globals.  We do
  1015. // this so that the information is available in our item handler proc.
  1016. //
  1017. // Also, store the GX item handler, and replace it with our own.  This
  1018. // will enable us to service non-dctl items in HandleStlDlogItems, and
  1019. // still let GX handle the dctls items.
  1020.  
  1021.     oldResFile = CurResFile();
  1022.     UseResFile(GXGetMessageHandlerResFile());
  1023.  
  1024.     optionsDialog = GetNewDialog(r_OptionsDialog, nil, (WindowPtr) -1);
  1025.     (*dlogGlobalsHdl)->optionsDialog = optionsDialog;
  1026.     require_action(optionsDialog != nil, GetNewDialog_Failed, err = resNotFound;);
  1027.  
  1028.     (*dlogGlobalsHdl)->originalItemProc = pDlg->pItemProc;
  1029.     pDlg->pItemProc = (PItemProcPtr) HandleStlDlogItems;
  1030.  
  1031.  
  1032. // Get the job's default format's collection, and from that get the
  1033. // horizontal and vertical flip settings.  If we can't find either,
  1034. // interpret that as "don't flip" in the appropriate direction.
  1035.  
  1036.     pageFormat = GXGetJobFormat(GXGetJob(), 1);
  1037.  
  1038.     itemSize = sizeof(gxFlipPageHorizontalInfo);
  1039.  
  1040.     err = GetFmtCollectionItem(&hFlipInfo, &itemSize, gxFlipPageHorizontalTag,
  1041.                                gxPrintingTagID, pageFormat);
  1042.  
  1043.     if (err) hFlipInfo.flipHorizontal = false;
  1044.  
  1045.     itemSize = sizeof(gxFlipPageVerticalInfo);
  1046.     
  1047.     err = GetFmtCollectionItem(&vFlipInfo, &itemSize, gxFlipPageVerticalTag,
  1048.                                gxPrintingTagID, pageFormat);
  1049.  
  1050.     if (err)
  1051.     {
  1052.         vFlipInfo.flipVertical = false;
  1053.         err = noErr;
  1054.     }
  1055.  
  1056. // Create our global structure to hold handles to the four flip
  1057. // pictures that we draw in the options dialog.  Also store this
  1058. // pointer in our dialog globals, so that we can access it from
  1059. // HandleStlDlogItems.
  1060.  
  1061.     flippedPicts = (FourPicts *) NewPtrSysClear(sizeof(FourPicts));
  1062.     (*dlogGlobalsHdl)->flippedPicts = flippedPicts;
  1063.  
  1064.  
  1065. // Set up the current flipping field in our data structure to reflect
  1066. // the type of flipping that's currently set-- 0 = no flipping,
  1067. // 1 = horizontal flipping, 2 = vertical flipping, 3 = horizontal and
  1068. // vertical flipping.  Based on the current flipping, mark the
  1069. // appropriate dialog checkboxes.
  1070.  
  1071.     flippedPicts->curFlipping = hFlipInfo.flipHorizontal
  1072.                                 + 2 * (char) vFlipInfo.flipVertical;
  1073.  
  1074.     SetCurFlip(optionsDialog, flippedPicts->curFlipping);
  1075.  
  1076.  
  1077. // Set up the current flipping field in our data structure to reflect
  1078. // the type of flipping.  When done, restore the original resource file
  1079. // and exit.
  1080.  
  1081.     flippedPicts->pict[0] = (PicHandle) Get1Resource('PICT', p_Normal);
  1082.     nrequire((err = ResError()), CouldNotLoadPict);
  1083.     flippedPicts->pict[1] = (PicHandle) Get1Resource('PICT', p_HFlip);
  1084.     nrequire((err = ResError()), CouldNotLoadPict);
  1085.     flippedPicts->pict[2] = (PicHandle) Get1Resource('PICT', p_VFlip);
  1086.     nrequire((err = ResError()), CouldNotLoadPict);
  1087.     flippedPicts->pict[3] = (PicHandle) Get1Resource('PICT', p_HVFlip);
  1088.     err = ResError();
  1089.  
  1090. CouldNotLoadPict:
  1091. GetNewDialog_Failed:
  1092.     UseResFile(oldResFile);
  1093.  
  1094. CreateAndStoreGlobals_Failed:
  1095.     return err;
  1096. }
  1097.  
  1098.  
  1099. // HandleStlDlogItems is our item handling routine for the style dialog.
  1100. // The only item we handle is the "options" button, which brings up
  1101. // the options dialog we've added.  All other items are passed to
  1102. // the GX item handler, since they are in our dctl resource.  This
  1103. // way, we get the benefits of dctls, but we can still support
  1104. // non-dctl controls.
  1105.  
  1106. pascal void HandleStlDlogItems(TPPrDlg pDlg, short itemNo)
  1107. {
  1108.  
  1109. // If the "options" button was hit, go handle it.  Otherwise, pass
  1110. // control to the GX dialog item handler routine (which we stored in
  1111. // InitStlDlogData).
  1112.  
  1113.     switch (itemNo)
  1114.     {
  1115.         case r_OptionsButton:
  1116.             DoOptionsDialog();
  1117.             break;
  1118.  
  1119.         default:
  1120.         {
  1121.             DialogGlobalsHdl    dlogGlobalsHdl;
  1122.             Ptr                    *originalItemProc;
  1123.             
  1124.             dlogGlobalsHdl = GetDialogGlobals();
  1125.  
  1126.             if (dlogGlobalsHdl != nil)    // It better not!!
  1127.             {
  1128.                 originalItemProc = (*dlogGlobalsHdl)->originalItemProc;
  1129.                 ((pascal void (*) (TPPrDlg, short)) originalItemProc) (pDlg, itemNo);
  1130.             }
  1131.         }
  1132.     }
  1133. }
  1134.  
  1135.  
  1136. // DoOptionsDialog is our routine to get, display and handle the
  1137. // options dialog (which is accessible from our style dialog).
  1138.  
  1139. void DoOptionsDialog()
  1140. {
  1141.     DialogPtr            optionsDlog;
  1142.     GrafPtr                oldPort;
  1143.     short                itemHit;
  1144.     char                oldSettings;
  1145.     DialogGlobalsHdl    dlogGlobalsHdl;
  1146.  
  1147. // Retrieve the pointer to our dialog, which we stored during
  1148. // InitStlDlogData.  Save the old grafport, display the window,
  1149. // select it, and set it as the current grafport.
  1150.  
  1151.     dlogGlobalsHdl = GetDialogGlobals();
  1152.     require(dlogGlobalsHdl != nil, NoGlobals);
  1153.     optionsDlog = (*dlogGlobalsHdl)->optionsDialog;
  1154.  
  1155.     GetPort(&oldPort);
  1156.     ShowWindow(optionsDlog);
  1157.     SelectWindow(optionsDlog);
  1158.     SetPort(optionsDlog);
  1159.  
  1160.  
  1161. // Save the current flip settings, in case the user cancels after
  1162. // changing them, then go into a ModalDialog loop until the user
  1163. // hits OK or cancel.
  1164.  
  1165.     oldSettings = GetCurFlip(optionsDlog, d_HFlip, d_VFlip);
  1166.  
  1167.     do
  1168.     {
  1169.         ModalDialog(OptionsDlogFilterProc, &itemHit);
  1170.         HandleOptionsDlogItems(itemHit);
  1171.         GXJobIdle();
  1172.     }
  1173.     while ((itemHit != ok) && (itemHit != cancel));
  1174.  
  1175.  
  1176. // Hide the dialog (we don't dispose of it until DisposeStlDlogData,
  1177. // since the user may want to go back to the dialog again).  Also,
  1178. // select the old window (the style dialog) and restore that as the
  1179. // current port.  If the user cancelled, store the original flip
  1180. // setting back in the job.
  1181.  
  1182.     HideWindow(optionsDlog);
  1183.     SelectWindow(oldPort);
  1184.     SetPort(oldPort);
  1185.  
  1186.     if (itemHit == cancel)
  1187.         SetCurFlip(optionsDlog, oldSettings);
  1188.  
  1189. NoGlobals:;
  1190. }
  1191.  
  1192.  
  1193. // OptionsDlogFilterProc is our ModalDialog filter proc for the
  1194. // options dialog.  It handles updating our dialog's items.
  1195.  
  1196. pascal Boolean OptionsDlogFilterProc(DialogPtr theDialog, EventRecord *theEvent,
  1197.                                      short *itemHit)
  1198. {
  1199.     short        itemType;
  1200.     Handle        itemH;
  1201.     Rect        itemBox;
  1202.  
  1203. #pragma unused(itemHit);
  1204.  
  1205. // If we're updating, draw the item for the line at the top of
  1206. // the dialog, a picture demonstrating the effect of the current
  1207. // flip settings, and the OK button outline.  We still return false
  1208. // because we want the DialogMgr to handle updating the rest of the
  1209. // dialog.
  1210.  
  1211.     if (theEvent->what == updateEvt)
  1212.     {
  1213.         GetDItem(theDialog, d_LineItem, &itemType, &itemH, &itemBox);
  1214.         MoveTo(itemBox.left, itemBox.top);
  1215.         LineTo(itemBox.right, itemBox.top);
  1216.         MoveTo(itemBox.left, itemBox.bottom);
  1217.         LineTo(itemBox.right, itemBox.bottom);
  1218.     
  1219.         DrawFlippedPict();
  1220.     
  1221.         GetDItem(theDialog, ok, &itemType, &itemH, &itemBox);
  1222.         PenSize(3, 3);
  1223.         InsetRect(&itemBox, -4, -4);
  1224.         FrameRoundRect(&itemBox, 16, 16);
  1225.         PenSize(1, 1);
  1226.     }
  1227.     
  1228.     return false;
  1229. }
  1230.  
  1231.  
  1232. // HandleOptionsDlogItems is our ModalDialog item handler for the
  1233. // options dialog.  Note that if this dialog had items that could
  1234. // be controlled through a dctl, we wouldn't even need this routine.
  1235. // We could have made the options dialog a "DialogBtn" dctl item,
  1236. // and had a  dctl which instructed how to handle the options dialog.
  1237. // We're implementing a totally non-dctl dialog here primarily as a
  1238. // demonstration (note that there is support for handling page
  1239. // flipping via dctl items, so you could handle the options via dctls.
  1240. // But, then we wouldn't be able to use our way-cool camel picture.
  1241. // Cascading dialogs must be totally dctl-driven, or not use dctls
  1242. // at all).
  1243.  
  1244. void HandleOptionsDlogItems(short itemNo)
  1245. {
  1246.     short                itemType;
  1247.     Handle                itemH;
  1248.     Rect                itemBox;
  1249.     DialogPtr            theDialog;
  1250.     DialogGlobalsHdl    dlogGlobalsHdl;
  1251.  
  1252. // Retrieve our dialog globals.
  1253.  
  1254.     dlogGlobalsHdl = GetDialogGlobals();
  1255.     require(dlogGlobalsHdl != nil, NoGlobals);
  1256.  
  1257. // Get the options dialog.  If the item hit was one of the flipping
  1258. // checkboxes, toggle it's value and redraw the dialog's picture.
  1259.  
  1260.     theDialog = (DialogPtr) (*dlogGlobalsHdl)->optionsDialog;
  1261.     
  1262.     switch (itemNo)
  1263.     {
  1264.         case d_HFlip:
  1265.         case d_VFlip:
  1266.             GetDItem(theDialog, itemNo, &itemType, &itemH, &itemBox);
  1267.             ToggleControl((void **) itemH);
  1268.             DrawFlippedPict();
  1269.             break;
  1270.     }
  1271.     
  1272. NoGlobals:;
  1273. }
  1274.  
  1275.  
  1276. // ToggleControl toggles a control on or off.  It's useful for controls
  1277. // like checkboxes or radio buttons, which can only have a value of 0
  1278. // or 1.  The function takes a "void **" so that we don't have to
  1279. // typecast the handle returned from GetDItem before calling this routine.
  1280.  
  1281. void ToggleControl(void **itemH)
  1282. {
  1283.     short ctlVal = GetCtlValue((ControlHandle) itemH);
  1284.  
  1285.     ctlVal = (ctlVal == 1)? 0: 1;
  1286.     SetCtlValue((ControlHandle) itemH, ctlVal);
  1287. }
  1288.  
  1289.  
  1290. // DrawFlippedPict draws a picture in our options dialog which demonstrates
  1291. // the effect of the flip settings currently selected there.
  1292.  
  1293. void DrawFlippedPict()
  1294. {
  1295.     DialogPtr            theDialog;
  1296.     FourPicts            *flippedPicts;
  1297.     char                curFlipping;
  1298.     short                itemType;
  1299.     Handle                itemH;
  1300.     Rect                itemBox;
  1301.     DialogGlobalsHdl    dlogGlobalsHdl;
  1302.  
  1303. // Retrieve our dialog globals.
  1304.  
  1305.     dlogGlobalsHdl = GetDialogGlobals();
  1306.     require(dlogGlobalsHdl != nil, NoGlobals);
  1307.  
  1308. // Get our options dialog and, from that, the user item where we'll draw
  1309. // our picture.
  1310.  
  1311.     theDialog = (*dlogGlobalsHdl)->optionsDialog;
  1312.     GetDItem(theDialog, d_FlipPict, &itemType, &itemH, &itemBox);
  1313.  
  1314.  
  1315. // Get the current flip setting, store it in case it's changed, and then
  1316. // locate and draw the appropriate PICT.  Afterwards, draw a frame around
  1317. // the picture.
  1318.  
  1319.     curFlipping = GetCurFlip(theDialog, d_HFlip, d_VFlip);
  1320.     flippedPicts = (*dlogGlobalsHdl)->flippedPicts;
  1321.     flippedPicts->curFlipping = curFlipping;
  1322.     DrawPicture(flippedPicts->pict[curFlipping], &itemBox);
  1323.  
  1324.     InsetRect(&itemBox, -1, -1);
  1325.     FrameRect(&itemBox);
  1326.  
  1327. NoGlobals:;
  1328. }
  1329.  
  1330.  
  1331. // SetCurFlip checks/unchecks the flip checkboxes in the options
  1332. // dialog, based on the char passed.   The passed value is
  1333. // interpreted like so:
  1334. //
  1335. //    curFlipping == 0 -- no flipping.
  1336. //    curFlipping == 1 -- horizontal flipping.
  1337. //    curFlipping == 2 -- vertical flipping.
  1338. //    curFlipping == 3 -- horizontal & vertical flipping.
  1339.  
  1340. void SetCurFlip(DialogPtr theDialog, char curFlipping)
  1341. {
  1342.     short        itemType;
  1343.     Handle        itemH;
  1344.     Rect        itemBox;
  1345.  
  1346.     GetDItem(theDialog, d_HFlip, &itemType, &itemH, &itemBox);
  1347.     SetCtlValue((ControlHandle) itemH, (curFlipping & 0x01));
  1348.     GetDItem(theDialog, d_VFlip, &itemType, &itemH, &itemBox);
  1349.     SetCtlValue((ControlHandle) itemH, (curFlipping & 0x02));
  1350. }
  1351.